/*
* Class Name: iFulfillMoveNextController
* Author: Accenture IDC | Bhumika Udani
* Date: 06-June-2011
* Requirement/Project Name: ifulfill
* Requirement/Project Description: Handles forward movement of FI through the workflow
* Bhumika Udani     v 2.1     dt 02 November 2011    Fixed list has no rows for assignment exception in immediateNextFunction method
* Bhumika Udani     v 2.2     dt 17 November 2011    removed hard coded string variable 'skip'
* Sravanthi Vendoti v 2.3     dt 21 November 2011       
* Sravanthi Vendoti v 2.4     dt 23 November 2011    Corrected the Task sequence order while inserting  records into the Task History Table during skip Operation and corrected Skip logic.
* Bhumika Udani     v 2.5     dt 23 November 2011    Added order by sequence__c for populating skipped tasks on Vf page   
* Bhumika Udani     v 2.6     dt 28 November 2011    Removed assigning fitem owner id to task instruction as Sayeed's email
* Sravanthi Vendoti v 2.7     dt 13 December 2011    Corrected the Next Task Sequence order in Move next popup window (Updated the query)  
* Bhumika Udani     v 2.8     dt 13 December 2011    Removed condition sequence=1 in the Task fetch query for Skip Function.
**/

public with sharing class iFulfillMoveNextController {

    public Fullfilment_Item__c fItem = new Fullfilment_Item__c();
    list<Wokflow_Steps__c> nTaskList = new List<Wokflow_Steps__c>();
    List<Workflow_Stage__c> workflowStage= new List<Workflow_Stage__c>();         
    List<Fullfilment_Item__c> skipFullfilmentList = new List<Fullfilment_Item__c>();
    List<Wokflow_Steps__c> selectStepOption = new List<Wokflow_Steps__c>(); 

    /**getter setters **/
    Public boolean errorFlag{get;set;} 
    Public string selStage{get;set;} 
    public string selstep{get;set;}
    Public String sReason{get;set;} 
    public string stype{get;set;}
    public boolean assignedWFC{get;set;}
    Public string description{get;set;} 
    public List<SelectOption> nextAssignmentGroup {get;set;}
    public string  assignGroup{get;set;}      
    public boolean skip{get;set;}
    public boolean assignMe{get;set;}    
    Public List<SelectOption> nextTaskList{get;set;}
    Public List<SelectOption> NextFunc{get;set;}
    Public List<SelectOption> NextTask{get;set;}
    Public List<SelectOption> preTaskList{get;set;}
    Public Boolean UserisPartOfNextGroup  {get;set;}                
         
     public List<SelectOption> getselReason() {        
         List<SelectOption> selOptReason = new List<SelectOption>();                     
         selOptReason.add(new SelectOption('General','General'));        
         selOptReason.add(new SelectOption('Skip','Skip'));
         return selOptReason;
     }
    
    
    /** Constructor **/
    public iFulfillMoveNextController (ApexPages.StandardController controller) 
    {
        fItem = (Fullfilment_Item__c)controller.getRecord();
        UserisPartOfNextGroup = true;
        assignMe = false;
        assignedWFC = false;
        errorFlag = true;
     }
    
    public pagereference dummy(){
            return null;    
    }

    /** method is fired onLoad of the moveNext VF ***/
    public pagereference immediateNextFunction(){             
             NextFunc = new List<SelectOption>();         
             nextTaskList = new List<SelectOption>(); 
             list<Workflow_Stage__c> wsList = new list<Workflow_Stage__c>();        
             List<WF_Assignment_Group__c> wfAssignGroupList = null;                                  
             
             /** workflow coordinator default checked if Fitem belongs to Out of Region**/
             if(fItem.Region__c == IfullfillTextConstant.FI_WORKFLOW_OOR_REG)  
                     assignedWFC = true;
             else    
                     assignedWFC = false;             
              
             /** Condition checking to make sure current Stage is populated   **/
             if(fItem.Current_Stage__c !=null){
                               
                 stype=IfullfillTextConstant.FI_GENERAL;        
             
                 /** Checking if there are any more tasks left in current function**/
                 if(fItem.Current_Step__c!=null){
                     nTaskList=[select id,Is_Last_Task__c,Dashboard_Function__c, Name from Wokflow_Steps__c where Wokflow_Stage_Name__c=:fItem.Current_Stage__c and Sequence__c =:(fItem.Current_Step__r.Sequence__c + 1)  ];            
                     system.debug('Next Task List'+nTaskList);
                 }                      
                 System.debug( 'nTaskList'+nTaskList.size());       
                 if(nTaskList.size()>0){
                 /** Display remaining tasks contained in function. **/
                       system.debug(nTaskList.size());                                             
                       for(Wokflow_Steps__c st : nTaskList){
                           nextTaskList.add(new SelectOption(st.id,st.Name));
                       } 
                       System.debug('fItem.Current_Stage__c ..'+fItem.Current_Stage__c+'Function Name'+fItem.Current_Function_Name__c);                          
                       NextFunc.add(new SelectOption(fItem.Current_Stage__c,fItem.Current_Function_Name__c));                           

                  }
                 else{  
                 
                 /** No More tasks in Current Function. Retrieve the next Function in sequence       **/
                 
                     wsList  = [select id,Is_Last_Function__c,Name from Workflow_Stage__c where Workflow_Code__c=:fItem.Workflow_Code__c and Sequence__c = :(fItem.Current_Stage__r.sequence__c + 1) limit 1 ];                         
                     NextFunc.add(new SelectOption(wsList[0].id,wsList[0].Name));                                                                                        
                     nextAssignmentGroup  = new List<SelectOption>();  
                     if(wsList.size()>0){
                      /*** Retrieve the assignment groups for the next function**/
                     
                         for(WF_Assignment_Group__c wfAssignGroupObj: [Select AG_Definition__r.ID, AG_Definition__r.name  ,AG_Definition__c from WF_Assignment_Group__c where Workflow_Function__c = :wsList[0].id]){
                             nextAssignmentGroup.add(new SelectOption(wfAssignGroupObj.AG_Definition__c,wfAssignGroupObj.AG_Definition__r.name) );
                         }                               
                      } 
                      /*** Retrieve the list of tasks for the  next function***/
                      Wokflow_Steps__c nextFunctionTask = [select id,Dashboard_Function__c,Is_Last_Task__c, Name from Wokflow_Steps__c where Wokflow_Stage_Name__c = :wsList[0].id  and Sequence__c = 1];
                      nextTaskList.add(new SelectOption(nextFunctionTask.id,nextFunctionTask.Name));                                                                                                                                                             
                 }
            }

            
            if(nextFunc.size() > 0){
                 selStage = nextFunc.get(0).getValue();//set the function as default value             
            }
             
            if(nextTaskList.size() > 0){
                selstep = nextTaskList.get(0).getValue();//set default value on task
                reArrangeAssignmentGroup();
            }
                             
            return null;
         }  
         
     /**Method called on 'Skip'     **/
     public void skipFunction(){
         
        list<Workflow_Stage__c> nFunctionList= new list<Workflow_Stage__c>();          
        list<Wokflow_Steps__c> nTaskList= new list<Wokflow_Steps__c>();     
        NextFunc.clear();      
        nextTaskList.clear();            
        
        ApexPages.Message msg= new ApexPages.Message(ApexPages.Severity.Error, 'You are on the last function');           
        
           if(skip==true){ 
           
           /** if skip is true get all the Functions greater than current sequence           **/
               if(fItem.Current_Stage__r.Is_Last_Function__c){
                    nFunctionList = [select id,Name,Is_Last_Function__c,Sequence__c,Task_Target_Days__c from Workflow_Stage__c where Workflow_Code__c=:fItem.Workflow_Code__c and Sequence__c = :(fItem.Current_Stage__r.sequence__c) ];
                    nTaskList =[select sequence__c,id,Is_Last_Task__c,Dashboard_Function__c, Name from Wokflow_Steps__c where Wokflow_Stage_Name__c =:fItem.Current_Stage__c and sequence__c > :(Integer.Valueof(fItem.Current_Step__r.sequence__c )) order by sequence__c ASC];                     
                }                                                     
               else {
                   nTaskList =[select sequence__c,id,Is_Last_Task__c,Dashboard_Function__c, Name from Wokflow_Steps__c where Wokflow_Stage_Name__c =:fItem.Current_Stage__c and sequence__c > :(Integer.Valueof(fItem.Current_Step__r.sequence__c )) order by sequence__c ASC];                           

                   /** check to find out if current function has to be displayed**/
                   if(nTaskList.size()>0 ) 
                    nFunctionList = [select id,Name,Is_Last_Function__c,Sequence__c,Task_Target_Days__c from Workflow_Stage__c where Workflow_Code__c=:fItem.Workflow_Code__c and Sequence__c >= :fItem.Current_Stage__r.sequence__c order by sequence__c ASC  ];               
                   
                   else{
                   nFunctionList = [select id,Name,Is_Last_Function__c,Sequence__c,Task_Target_Days__c from Workflow_Stage__c where Workflow_Code__c=:fItem.Workflow_Code__c and Sequence__c >= :(fItem.Current_Stage__r.sequence__c + 1) order by sequence__c ASC  ];
                   nTaskList =[select Dashboard_Function__c,sequence__c,id,Is_Last_Task__c, Name from Wokflow_Steps__c where Wokflow_Stage_Name__c =:nFunctionList[0].id  order by sequence__c ASC];}                                    
               }                        
               for(Workflow_Stage__c ws : nFunctionList){
                         NextFunc.add(new SelectOption(ws.id,ws.Name));  
                         workflowStage.add(ws);       
               }
                for(Wokflow_Steps__c stp : nTaskList ){
                         nextTaskList.add(new SelectOption(stp.id,stp.Name));                    
                }    
               stype=IfullfillTextConstant.FI_SKIP;      
               system.debug('NEXT FUNCTION----->'+ NextFunc);                                  
            }
           else{ 
               /** when skip is unchecked **/
               stype=IfullfillTextConstant.FI_GENERAL;
               immediateNextFunction();}
      }


    /**Method to dynamically populate 'Next Task' based on the user selection of 'Next Func'        **/
     public void nextTask()
     {   
         list<Wokflow_Steps__c> nTask = new list<Wokflow_Steps__c>(); 
          List<SelectOption> stepOptions = new List<SelectOption>(); 
          if(fitem.current_stage__c == selStage)    
              //Updated the query to display the Next task( in the move Next pop up window) in sequence order )          
              nTask =[select id, name, Dashboard_Function__c,Sequence__c,Step__c,Target_Days__c from Wokflow_Steps__c where Wokflow_Stage_Name__c =:selStage and sequence__c > :fitem.current_step__r.sequence__c order by sequence__c];              
          else
               //Updated the query to display the Next task(in the move Next pop up window) in sequence order )
              nTask =[select id, name,Dashboard_Function__c,Sequence__c,Step__c,Target_Days__c from Wokflow_Steps__c where Wokflow_Stage_Name__c =:selStage order by sequence__c];
          for(Wokflow_Steps__c wt : nTask){
          
              stepOptions.add(new SelectOption(wt.id,wt.Name));
              selectStepOption.add(wt);         
          }           
          nextTaskList = stepOptions;                
          if(stepOptions.size() > 0){
                    
              SelectOption obj =  stepOptions.get(0);
              selstep= obj.getValue();              
          }        
          nextFunctionAssingmentGroup(); 
          reArrangeAssignmentGroup();
       }
       
    
    /**Method to update the existing fulfillment Item on click of 'Move'**/
    public pagereference updateFitem(){
          System.debug('first current function'+fItem.Current_Stage__c+'sequence'+fItem.Current_Step__r.Sequence__c);
            String currentFunction =fItem.Current_Stage__c;
            Decimal currentTaskSequence =fItem.Current_Step__r.Sequence__c;
        
            Workflow_Stage__c stg = [select id, name,Sequence__c,Task_Target_Days__c from Workflow_Stage__c where id =: selstage];
            Wokflow_Steps__c stp = [select id, Dashboard_Function__c,Sequence__c,name from Wokflow_Steps__c where id =: selstep];    
                    system.debug('Here ------>'+stg + 'I am in step --->'+ stp);
            string QueueName;         
            ApexPages.Message msg= new ApexPages.Message(ApexPages.Severity.Error, IfullfillTextConstant.WFCORD_KEEPWITHME_ERROR_MSG);
            if(assignMe && assignedWFC ){
                ApexPages.addMessage(msg);
                return null;
            }
            else{                                  
             System.debug('description '+description +'stype ..'+stype);
         
        /**For Skip Functionality- Use Fulfillment Item Owner to update FulfillmentTaskHistory Owner value.****/
            String oldFulfillmentItemOwnername =fItem.Owner_Reporting__c;
            ID oldFulfillmentItemOwnerID = fItem.ownerId ;
        
        if((stype==IfullfillTextConstant.FI_GENERAL && description != null && description != '') || (stype==IfullfillTextConstant.FI_SKIP && skip)){
            /**Create new task instruction record if skipped or if description is filled **/
             Task_Instruction__c tr = new Task_Instruction__c();            
             tr.Item_ID__c=fitem.id;
             tr.Description__c=description;          
             tr.Type__c=stype;
             tr.Previous_Next_Function__c=fItem.Current_Function_Name__c;                 
             tr.Previous_Next_Task__c=fItem.Current_Task_Name__c;
             tr.Current_Function__c=stg.name;
             tr.Current_Task__c=stp.name;
             /**commenting below line as per Sayeed's email,owner can be default **/
             /** tr.ownerid = fItem.ownerid;**/
             system.debug('OWNER ID------>' + fItem.ownerid);
             try{Insert tr;}
             Catch(dmlException e){GeneralCOnstants.mailAnyExceptionToMe('fItem.ownerid','updateFitem',e);}
        }
        if(!assignMe )//If keep it with me is not checked, Change the owner of FI to the default assignment group of the 'new task'
         {            
             if (!assignedWFC) { 
                 System.debug('assignGroup ..'+assignGroup);
                 List<Assignment_Group_Queues__c> selectedGroup = [select Name,QueueId__c from Assignment_Group_Queues__c where Assignment_Group_Name__c = :assignGroup];
                   System.debug('selectedGroup value'+selectedGroup);
                 if (selectedGroup.size() >0) {
                    
                     fItem.ownerId = selectedGroup[0].QueueId__c;
                     QueueName=selectedGroup[0].Name;
                 }
             }
             else{
                 System.debug('Else part workflow Coordinator'+fItem.Workflow_Coordinator__c);
                 fItem.ownerId = fItem.Workflow_Coordinator__c;
             }               
         }

        System.debug('Update Fitem')   ; 
        /**Update the FI with new func/task and timestamps                            **/
        if(fitem.Current_Stage__c !=null)   fitem.Current_Stage__c=selStage;        
        else{//ADD ERROR MSG
        return null;}
        if(fItem.Current_Step__c !=null)     fItem.Current_Step__c=selstep;
        else{//ADD ERROR MSG
        return null;}
        
        system.debug(fitem.Previous_Function_Sequence__c+ ''+ stg.Sequence__c);
        
         //Check if function is same, Task progressed                 
     /***    if(fitem.Previous_Function_Sequence__c == stg.Sequence__c){
                 if(fitem.Previous_Task_Sequence__c < stp.Sequence__c){
                         system.debug('Inside task progress'+fitem.In_Rework_Reject__c);   
                         fItem.In_Rework_Reject__c       = null;
                         fitem.Previous_Dashboard__c     = stp.Dashboard_Function__c;
                         fitem.Previous_Task__c          = stp.name;                 
                         fitem.Previous_Task_Sequence__c = stp.Sequence__c;
                         fItem.In_Rework_Reject__c       = null;
                         system.debug(fitem.In_Rework_Reject__c);
                         }
                 }
        if(fitem.Previous_Function_Sequence__c < stg.Sequence__c){
                         system.debug('Inside function progress'+fitem.In_Rework_Reject__c);   
                         fitem.In_Rework_Reject__c=null;
                         fitem.Previous_Dashboard__c     = stp.Dashboard_Function__c;
                         fitem.Previous_Task__c          = stp.name;                 
                         fitem.Previous_Task_Sequence__c = stp.Sequence__c;
                         fitem.Previous_Function__c      = stg.name;
                         fitem.Previous_Function_Sequence__c = stg.Sequence__c;
                        // fItem.In_Rework_Reject__c           =null;

        }    
        ***/
        if(assignMe||assignedWFC){
            /** if the owner on FI is 'User' keep the status as in progress**/
            fItem.Status__c =IfullfillTextConstant.FI_WORKFLOW_PROGRESS_STATUS;
            }          
       else{
            /** if owner is queue keep update status to Open **/   
            fItem.Status__c =IfullfillTextConstant.FI_WORKFLOW_OPEN_STATUS;
            }         
        fItem.Current_Stage_Start_Date__c = system.now();
        fItem.Current_Step_Start_Date__c = system.now();                       
                
        /** Tracks the 'Skipped' functions and Tasks in Fulfillment Task History**/
       if(stype==IfullfillTextConstant.FI_SKIP && skip){
          List<Workflow_Stage__c> selectStageList = new List<Workflow_Stage__c>();
          List<Wokflow_Steps__c> stepList = new List<Wokflow_Steps__c>();
          Map <ID,List<Wokflow_Steps__c>> skipStageMap = new Map<ID,List<Wokflow_Steps__c>>();

          for(Workflow_Stage__c stageOptionList:workflowStage){
             if(stageOptionList.id == selStage){
               break;
             }else{
               selectStageList.add(stageOptionList);
             }    
          }
          /** Fetch Tasks from workflow Step based on the sequence order .**/
          List <Wokflow_Steps__c> workflowSteplist =[select id, name,Wokflow_Stage_Name__c,Sequence__c,Target_Days__c,Dashboard_Function__c from Wokflow_Steps__c where Wokflow_Stage_Name__c in :selectStageList order by Wokflow_Stage_Name__r.Sequence__c,Sequence__c];  
          
          Set<ID> currentFunctionTaskSet= new Set<ID>();
          
          /** Retrieve the current Function's current Task  id and previous task ids of the current function.  **/
          for(Wokflow_Steps__c WT:[select id from Wokflow_Steps__c where Wokflow_Stage_Name__c = :currentFunction  and Sequence__c <=:currentTaskSequence]){
              currentFunctionTaskSet.add(WT.id);
          }
          System.debug('currentFunctionTaskSet'+currentFunctionTaskSet);
          Map <ID,List<Wokflow_Steps__c>> workflowStepMap = new Map<ID,List<Wokflow_Steps__c>>();
          
           for(Wokflow_Steps__c WT :workflowSteplist){    
              
              /**Not include current function's currents task and previous task into Map        **/
              
              if(WT.Wokflow_Stage_Name__c == currentFunction && currentFunctionTaskSet.size() >0 && currentFunctionTaskSet.contains(WT.ID)){
                   continue;
              }else{               
                 if(workflowStepMap.containsKey(WT.Wokflow_Stage_Name__c)){
                    workflowStepMap.get(WT.Wokflow_Stage_Name__c).add(WT);
                 }else{
                    workflowStepMap.put(WT.Wokflow_Stage_Name__c,new List<Wokflow_Steps__c>{WT});        
                 } 
              } 
         } 
            system.debug('workflowStepMap -----'+workflowStepMap);
          for(Workflow_Stage__c skipStageList:selectStageList){
              if(workflowStepMap.containsKey(skipStageList.id)){
                skipStageMap.put(skipStageList.id,workflowStepMap.get(skipStageList.id));         
              }  
          }
          system.debug('selectStageList' +selectStageList);
          
          if(selectStageList.size()>0 ){
            iFulfillTrackTaskHistory.createNewStepHistoryForSkip(fItem,selectStageList,skipStageMap,oldFulfillmentItemOwnername,oldFulfillmentItemOwnerID); // creates history records for 'skipped' functions
          }        
          for(Wokflow_Steps__c stepOptionList:selectStepOption){
              if(stepOptionList.id ==selstep){
                 break;
              }else{
                 stepList.add(stepOptionList);
              }
          }
          if(stepList.size()>0){        
             iFulfillTrackTaskHistory.createNewStepHistoryForRemainingCurrentTaskSkip(fItem,stg,stepList,oldFulfillmentItemOwnername,oldFulfillmentItemOwnerID); // Creates history records for 'skipped tasks'
          }                         
          fItem.Type__c = IfullfillTextConstant.FI_SKIP;        
        }
         
         //if(fitem.Previous_Function_Sequence__c < stg.Sequence__c){
         //fItem.In_Rework_Reject__c=null;
         try{update fItem;}
         Catch(dmlexception e){
             errorFlag = false;
             IfullfillTextConstant.parseExceptionMsg(e,'iFulfillMoveNextController','updateFItem');
             return null;
         }         
         return null;        
       }             
      }
      
      
    public void isUserPartOfNextAssignmentGroup(){
        UserisPartOfNextGroup = true;
        List <Assignment_Groups__c> groupMember = [select User__c from Assignment_Groups__c where  Group_Name__c =:assignGroup and user__c = :fItem.ownerID];             
        if(groupMember.size()> 0)
        {
            UserisPartOfNextGroup= false;
        }
        if(UserisPartOfNextGroup )
        {
            assignMe = false;
        }
    }
    
    
    public void nextFunctionAssingmentGroup()
    {   
        System.debug('Next Func Assignment Group' + selStage);  
        List<SelectOption> assignmentGroup= new List<SelectOption>();    
        List<WF_Assignment_Group__c> wfAssignGroupList  = [Select AG_Definition__r.name  ,AG_Definition__c from WF_Assignment_Group__c where Workflow_Function__c = :selStage];
                      
        for(WF_Assignment_Group__c wfAssignGroupObj: wfAssignGroupList  )
        {
            assignmentGroup.add(new SelectOption(wfAssignGroupObj.AG_Definition__c,wfAssignGroupObj.AG_Definition__r.name) );
        }
        nextAssignmentGroup  = assignmentGroup;
        intilizeAssignmentGroup();
               
     }
        
        
        
     private void intilizeAssignmentGroup()
     {
        assignGroup ='';     
        if(nextAssignmentGroup!=null && nextAssignmentGroup.size() > 0)
        {
             SelectOption obj =   nextAssignmentGroup.get(0);
             assignGroup = obj.getValue();
        }
        isUserPartOfNextAssignmentGroup();  
     }
        
        
     public void reArrangeAssignmentGroup()
     {
          String defaultAssignmentGrp = null;
          System.debug('selstep '+ selstep  );
          List<SelectOption > s = new  List<SelectOption >();
         
          if(selstep != null)
          {
               Wokflow_Steps__c workflowStep = [select id,Default_Group__c from Wokflow_Steps__c where id = :selstep];
               System.debug('Work Flow'+workflowStep);
               defaultAssignmentGrp = workflowStep.Default_Group__c;
               System.debug ('Selected Stage '+ selStage );
               if(defaultAssignmentGrp != null)
               {
                   if(selStage != null)
                   {
                        List<SelectOption> assignmentGroup= new List<SelectOption>();    
                        List<WF_Assignment_Group__c> wfAssignGroupList  = [Select AG_Definition__r.name,AG_Definition__c from WF_Assignment_Group__c where Workflow_Function__c = :selStage ];
                       
                        for(Integer i=0; i< wfAssignGroupList.size();i++)
                        {
                            WF_Assignment_Group__c obj = wfAssignGroupList.get(i);
                            if(obj!=null && defaultAssignmentGrp.equals(obj.AG_Definition__c))
                            { 
                                s.add(new SelectOption(obj.AG_Definition__c,obj.AG_Definition__r.name) );
                                wfAssignGroupList.remove(i);
                            }
                        }                    
                        for(Integer i=0; i< wfAssignGroupList.size();i++)
                        {
                            WF_Assignment_Group__c obj = wfAssignGroupList.get(i);                                                       
                                s.add(new SelectOption(obj.AG_Definition__c,obj.AG_Definition__r.name) );
                        
                        }
                    }
                    nextAssignmentGroup  = s;                        
                    
               }
          }
          intilizeAssignmentGroup();
     }  
}